<?php

namespace Trawind\Extension\Transformers\Custom;

use Illuminate\Database\Eloquent\Model;
use Trawind\Basics\Exceptions\LogicException;
use Trawind\Extension\Models\Custom\Field;
use Trawind\Extension\Models\Deploy\BusinessType;

trait CustomTransformer
{

    public $details;

    /**
     * @var array
     */
    public $fields = [];

    /**
     * @var array
     */
    public $remoteBusinessType = [];

    /**
     * @var array
     */
    public $localBusinessType = [];

    /**
     * @var array
     */
    public $remoteIds = [];


    public function __construct(int $businessTypeId)
    {
        parent::__construct($businessTypeId);
        $this->details = $this->getDetails();
        $this->fields = $this->details['fields'];
        $this->remoteBusinessType = $this->details['remoteBusinessType'];
        $this->localBusinessType = $this->details['localBusinessType'];
    }

    /**
     * @param  Model  $model
     * @return array
     * @throws LogicException
     */
    public function transform(Model $model): array
    {
        $data = [];
        foreach ($this->fields as $field) {
            $value = $model->{$field['name']} ?? $field['default'];
            //@note 关联类型，收集关联字段
            $this->widgetRelationHandle($field, $model, $data);

            //@note 枚举类型，转换枚举字段
            if ($field['widget_type_id'] === Field::WIDGET_TYPE_ENUM['field_widget_enmus'] && !is_null($field['enum'])) {
                $enumValues = array_column($field['enum']['values'], null, 'index');
                $enumIndex = $model->{$field['index_field']['name']} ?? null;
                $value = $enumValues[$enumIndex]['value'] ?? '';
                //@note 转换枚举多言语翻译
                if (!empty($enumLanguageValues = $enumValues[$enumIndex]['languages'] ?? [])) {
                    $enumLanguageValues = array_column($enumLanguageValues, null, 'field');
                    $value = $enumLanguageValues['value']['content'] ?? '';
                }
            }

            //@note 日期/时间类型，转换对应时区
            if ($field['widget_type_id'] === Field::WIDGET_TYPE_ENUM['field_widget_date_time']) {
                $value = __date_time($model->{$field['name']} ?? null);
            }

            $data[$field['name']] = $value;
        }
        return $data;
    }

    /**
     * @param  array  $field
     * @param         $model
     * @param         $data
     * @return void
     * @throws LogicException
     */
    protected function widgetRelationHandle(array $field, $model, &$data): void
    {
        if ($this->isRelationField($field)) {
            if (is_null($field['index_field'])) {
                $relationship = $this->localBusinessType[$field['relation_business_type_id']];
                $relationshipArray = $model->{$relationship}->toArray();
                count($relationshipArray) === count($relationshipArray,
                    1) and LogicException::error("[{$relationship}] must `hasMany`");
                $data[$relationship] = $relationshipArray;

                if ($field['relation_field']['relation_field_id'] > 0) {
                    $subRelationField = $field['relation_field'];
                    $remoteBusinessTypeId = $subRelationField['relation_business_type_id'];
                    $indexIds = $model->{$relationship}->pluck($subRelationField['index_field']['name'])->toArray();
                    $remoteIds = $this->remoteIds[$remoteBusinessTypeId] ?? [];
                    $this->remoteIds[$remoteBusinessTypeId] = array_unique(array_merge($remoteIds, $indexIds));
                }
            } else {
                if ($field['relation_field_id'] > 0) {
                    $remoteIds = $this->remoteIds[$field['relation_business_type_id']] ?? [];
                    $remoteIds[] = $model->{$field['index_field']['name']};
                    $this->remoteIds[$field['relation_business_type_id']] = array_unique($remoteIds);
                }
            }
        }
    }

    /**
     * @param  array  $field
     * @return bool
     */
    private function isRelationField(array $field): bool
    {
        return in_array($field['widget_type_id'],[Field::WIDGET_TYPE_ENUM['field_widget_relation'],Field::WIDGET_TYPE_ENUM['field_widget_tree_relation']],true)
            && $field['relation_business_type_id'] > 0
            && $field['is_store'] === 0;
    }

    abstract protected function getDetails();

    protected function containerKey(int $businessTypeId): string
    {
        return static::class.'#'.$businessTypeId;
    }

    protected function collectWithParam($details): array
    {
        $localBusinessType = $remoteBusinessType = [];
        $queryers = array_column($details['business_type']['queryers'], null, 'relation_business_type_id');
        foreach ($details['fields'] as $fields) {
            if ($fields['field']['relation_field_id'] > 0) {
                $businessTypeId = $fields['field']['relation_business_type_id'];
                $fields['field']['relation_business_type']['service'] == config('app.name')
                    ? $localBusinessType[$businessTypeId] = $queryers[$businessTypeId]['relationship']
                    : $remoteBusinessType[$businessTypeId] = $fields['field']['relation_business_type'];

                if ($fields['field']['relation_field']['relation_field_id'] > 0) {
                    $subRelationField = $fields['field']['relation_field'];
                    $subBusinessTypeId = $subRelationField['relation_business_type_id'];
                    $subRelationField['relation_business_type']['service'] == config('app.name')
                        ? $localBusinessType[$subBusinessTypeId] = $queryers[$subBusinessTypeId]['relationship']
                        : $remoteBusinessType[$subBusinessTypeId] = $subRelationField['relation_business_type'];
                }
            }
        }

        return [$remoteBusinessType, $localBusinessType];
    }

    /**
     * @note 转换关联字段并组装，并携带出字段信息
     * @param  array  $data
     * @return array
     */
    final public function buildRelationFieldToData(array $data): array
    {
        $remoteResult = [];
        foreach ($this->remoteIds as $businessTypeId => $ids) {
            $remoteResult[$businessTypeId] = BusinessType::getEloquentByData($this->remoteBusinessType[$businessTypeId])->getListById($ids);
        }

        foreach ($data as &$item) {
            foreach ($this->fields as $key => $field) {
                if ($this->isRelationField($field)) {
                    if (is_null($field['index_field'])) {
                        $relationship = $this->localBusinessType[$field['relation_business_type_id']];
                        $first = array_shift($item[$relationship]);
                        if ($field['relation_field']['relation_field_id'] > 0) {
                            $subRelationField = $field['relation_field'];
                            $indexField = $subRelationField['index_field']['name'];
                            $relationField = $subRelationField['relation_field']['name'];
                            $first[$subRelationField['name']] = $remoteResult[$subRelationField['relation_business_type_id']][$first[$indexField]][$relationField];
                            $item[$field['name']] = $first[$subRelationField['name']];
                            unset($item[$relationship]);
                        }
                    } else {
                        $indexField = $field['index_field']['name'];
                        $relationField = $field['relation_field']['name'];
                        $item[$field['name']] = $remoteResult[$field['relation_business_type_id']][$item[$indexField]][$relationField]??'';
                    }
                }
            }
        }
        return $data;
    }

}